﻿#pragma once

#include "../MirGraphics/MLibrary.h"
#include "MapObject.h"
#include "../../Shared/Enums.h"
#include <string>
#include <vector>
#include <optional>
#include "../../tangible_event.h"

using namespace Client::MirGraphics;
using namespace Client::MirScenes;
using namespace Client::MirSounds;

namespace Client::MirObjects
{
    class Effect
    {
    public:
        MLibrary *Library;

        int BaseIndex = 0, Count = 0, Duration = 0;
        long long Start = 0;

        int CurrentFrame = 0;
        long long NextFrame = 0;

        Point *Source;
        MapObject *Owner;

        int Light = 6;
        Color *LightColour = Color::White;

        bool Blend = true;
        float Rate = 1.0F;
        Point *DrawLocation;
        bool Repeat = false;
        long long RepeatUntil = 0;

        bool DrawBehind = false;

        long long CurrentDelay = 0;
        long long Delay = 0;

        TangibleEvent<EventHandler> *Complete = new TangibleEvent<EventHandler>();
        TangibleEvent<EventHandler> *Played = new TangibleEvent<EventHandler>();

        virtual ~Effect()
        {
            delete Library;
            delete Source;
            delete Owner;
            delete LightColour;
            delete DrawLocation;
        }

        Effect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, long long starttime = 0, bool drawBehind = false);
        Effect(MLibrary *library, int baseIndex, int count, int duration, Point *source, long long starttime = 0, bool drawBehind = false);

        void SetStart(long long start);

        virtual void Process();
        virtual void Remove();

        virtual void Draw();

        void Clear();
    };

    class Missile : public Effect
    {
    public:
        static std::vector<Missile*> Missiles;
        MapObject *Target;
        Point *Destination;
        int Interval = 0, FrameCount = 0, Skip = 0;
        int Direction = 0;
        bool Explode = false;


        virtual ~Missile()
        {
            delete Target;
            delete Destination;
        }

        Missile(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, Point *target, bool direction16 = true);

        Missile(MLibrary *library, int baseIndex, int count, int duration, Point *source, Point *target);

        void Process() override;
        void Remove() override;
        void Draw() override;

    };

    class InterruptionEffect : public Effect
    {
    public:
        static std::vector<InterruptionEffect*> effectlist;
    private:
        bool noProcess = false;

    public:
        InterruptionEffect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, bool blend, long long starttime = 0);

        void Process() override;

        void Remove() override;

        void Draw() override;

        static int GetOwnerEffectID(unsigned int objectID);
    };

    class ElementsEffect : public Effect
    {
    private:
        int myType = 0; //1 = green orb, 2 = blue orb, 3 = red orb, 4 = mixed orbs
        long long killAt = 0; //holds the exp value for 4 orbs : kills all orbs when myType 4 is reached
        bool loopit = false; //soundloop

    public:
        ElementsEffect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, bool blend, int elementType, int killtime, bool loopon = false);

        void Process() override;

    private:
        void StartSound();

        void StopSounds();

    public:
        void Remove() override;

        void Draw() override;
    };

    class DelayedExplosionEffect : public Effect
    {
    public:
        static std::vector<DelayedExplosionEffect*> effectlist;
        int stage = 0;

        DelayedExplosionEffect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, bool blend, int Stage, long long until);

        void Process() override;

        void Remove() override;

        void Draw() override;

        static int GetOwnerEffectID(unsigned int objectID);
    };

    class SpecialEffect : public Effect
    {
    public:
        unsigned int EffectType = 0;

        SpecialEffect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, bool blend, bool drawBehind, unsigned int type);

        void Process() override;
    };

    class BuffEffect : public Effect
    {
    public:
        BuffType BuffType = static_cast<BuffType>(0);

        BuffEffect(MLibrary *library, int baseIndex, int count, int duration, MapObject *owner, bool blend, BuffType buffType);

        void Process() override;
    };

    class TrackableEffect : public Effect
    {
    public:
        static std::vector<TrackableEffect*> effectlist;
        std::string EffectName = "default";

        TrackableEffect(Effect *baseEffect, const std::string &effName = "null");

        static int GetOwnerEffectID(unsigned int objectID, const std::string &effectName = "null");

        void Process() override;

        void Remove() override;

        void RemoveNoComplete();

    };

    class LightEffect : public Effect
    {
    public:
        LightEffect(int duration, MapObject *owner, long long starttime = 0, int lightDistance = 6, std::optional<Color*> &lightColour = std::nullopt);

        LightEffect(int duration, Point *source, long long starttime = 0, int lightDistance = 6, std::optional<Color*> &lightColour = std::nullopt);

        void Process() override;

        void Draw() override;
    };

}
